﻿using System;
using System.Collections.Generic;
using Volo.Abp.Data;
using Volo.Abp.Domain.Entities.Auditing;

namespace Volo.Payment.Requests
{
    public class PaymentRequest : CreationAuditedAggregateRoot<Guid>
	{
		public virtual ICollection<PaymentRequestProduct> Products { get; private set; }

		public PaymentRequestState State { get; private set; }

		public string Currency { get; set; }

		public string Gateway { get; set; }

		public string FailReason { get; private set; }

		public PaymentRequest(Guid id)
		{
			this.Id = id;
			this.Products = new List<PaymentRequestProduct>();
		}

		public PaymentRequestProduct AddProduct(string code, string name, float unitPrice, int count = 1, float? totalPrice = null, Dictionary<string, IPaymentRequestProductExtraParameterConfiguration> extraProperties = null)
		{
			PaymentRequestProduct paymentRequestProduct = new PaymentRequestProduct(this.Id, code, name, unitPrice, count, totalPrice);
			if (extraProperties != null)
			{
				foreach (KeyValuePair<string, IPaymentRequestProductExtraParameterConfiguration> keyValuePair in extraProperties)
				{
					paymentRequestProduct.SetProperty(keyValuePair.Key, keyValuePair.Value, true);
				}
			}
			this.Products.Add(paymentRequestProduct);
			return paymentRequestProduct;
		}

		public void Complete(bool triggerEvent = true)
		{
			if (this.State != PaymentRequestState.Waiting)
			{
				throw new ApplicationException(string.Format("Can not complete a payment in '{0}' state!", this.State));
			}
			this.State = PaymentRequestState.Completed;
			if (triggerEvent)
			{
				this.AddDistributedEvent(this.GetPaymentRequestCompletedEto());
			}
		}

		private object GetPaymentRequestCompletedEto()
		{
			var list = new List<PaymentRequestProductCompletedEto>();
			foreach (var paymentRequestProduct in this.Products)
			{
				list.Add(new PaymentRequestProductCompletedEto
				{
					Code = paymentRequestProduct.Code,
					Count = paymentRequestProduct.Count,
					Name = paymentRequestProduct.Name
				});
			}
			var paymentRequestCompletedEto = new PaymentRequestCompletedEto(this.Id, this.Gateway, this.Currency, list);
			foreach (var keyValuePair in this.ExtraProperties)
			{
				paymentRequestCompletedEto.Properties[keyValuePair.Key] = keyValuePair.Value;
			}
			return paymentRequestCompletedEto;
		}

		public void Failed(string reason = null)
		{
			if (this.State != PaymentRequestState.Waiting)
			{
				throw new ApplicationException(string.Format("Can not fail a payment in '{0}' state!", this.State));
			}
			this.State = PaymentRequestState.Failed;
			this.FailReason = reason;
		}
	}
}
